package com.lou1052.redis.jedis.api;

import com.google.common.collect.Lists;
import com.lou1052.core.serializer.Serializer;
import redis.clients.jedis.BinaryJedisCommands;
import redis.clients.jedis.BinaryScriptingCommands;
import redis.clients.jedis.JedisCommands;
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.util.SafeEncoder;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 统一的Jedis Api（Jedis，ShardedJedis，ClusterJedis）
 * Created with IntelliJ IDEA.
 * User: liuqing
 * Date: 2015/10/17
 * Time: 20:14
 * 1 支持针对对象的直接操作
 * 所有xxObject和xxData 方法 的value参数值不支持String ，可以根据key的后缀选择对应的序列化方式 :jdk :kryo :fst
 * 所有的String和byte[]的转换统一使用 SafeEncoder.encode
 * xxObject和xxData的区别是
 * xxObject序列化带类型信息 反序列化时不需要Class
 * xxData 序列化不带类型信息 反序列化时使用Class
 * 需要成对使用！！！存取对应
 *
 * 2 可配置无阻塞的pool，及线程绑定的poolObject
 *
 * 3 集群支持密码
 *
 * 4 两种使用方式： 全局对象（facroeyBean包实现），资源对象（source包实现）
 *
 */
public interface JedisApi  extends BinaryJedisCommands,JedisCommands,RunCommands,ScriptCommands,AutoCloseable{

    /**
     * 运行时异常
     * @throws JedisException
     */
    void close() throws JedisException;

    /**
     * 获取序列化器
     * @return
     */
    Serializer getSerializer(String key);

    /**
     * 获取值的编码工具
     * 可以根据key的类型决定使用不用类型的编码（序列化）
     * @return
     */
    default Function<Object,byte[]> getDataEncode(String key){
        return (object)->getSerializer(key).serData(object);
    }

    /**
     * 获取值的解码工具
     * 可以根据key的类型使用对应的解码工具（反序列化）
     * @return
     */
    default <T> BiFunction<byte[],Class<T>,T> getDataDecode(String key){
        return (bytes,clazz)->getSerializer(key).deserData(bytes, clazz);
    }

    /**
     * 获取值的编码工具
     * 可以根据key的类型决定使用不用类型的编码（序列化）
     * @return
     */
    default Function<Object,byte[]> getObjectEncode(String key){
        return (object)->getSerializer(key).serObject(object);
    }

    /**
     * 获取值的解码工具
     * 可以根据key的类型使用对应的解码工具（反序列化）
     * @return
     */
    default  Function<byte[],Object> getObjectDecode(String key){
        return (bytes)->getSerializer(key).deserObject(bytes);
    }

    /**
     * 得到具体的实现
     * @param clazz
     * @param <T>
     * @return 底层实现对象，若类型错误返回null
     */
    default <T> T unwrap(Class<T> clazz){
        return  (T)this;
    }

    /**
     * 执行脚本命令 调用ScriptCommands.eval(String script, String key, List<Object> args)
     * @param runInScript
     * @param <R>
     * @return
     */
    default <R> R run(RunInScript<R> runInScript) {
        return runInScript.callOn(this);
    }


    /**
     * 分布式的只支持单key
     * @param script
     * @param key
     * @param args
     * @return
     */
    default Object eval(String script, String key, List<Object> args){
        byte[] byteScript = SafeEncoder.encode(script);
        List<byte[]> byteKeys = Lists.newArrayList(SafeEncoder.encode(key));
        List<byte[]> byteArgs = args.stream().map((o) -> getObjectEncode(key).apply(o)).collect(Collectors.toList());
        Object result = this.run(key,(jedis -> jedis.eval(byteScript,byteKeys,byteArgs)));
        if(result instanceof byte[]){
            result = getObjectDecode(key).apply((byte[])result);
        }
        return result;
    }

    /**
     * 将字符串值 value 关联到 key 。如果 key 已经持有其他值， SET 就覆写旧值，无视类型。
     * 对于某个原本带有生存时间（TTL）的键来说， 当 SET 命令成功在这个键上执行时， 这个键原有的 TTL 将被清除
     * @param key
     * @param value
     * @return
     */
    default String setData(String key, Object value){
        return set(SafeEncoder.encode(key), getDataEncode(key).apply(value));
    }

    /**
     * EX second ：设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
     * PX millisecond ：设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
     * NX ：只在键不存在时，才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
     * XX ：只在键已经存在时，才对键进行设置操作。
     * @param key
     * @param value
     * @param nxxx
     * @param expx
     * @param time
     * @return
     */
    default String setData(String key, Object value, String nxxx, String expx, long time){
        return set(SafeEncoder.encode(key), getDataEncode(key).apply(value), SafeEncoder.encode(nxxx), SafeEncoder.encode(expx), time);
    }

    /**
     * 返回 key 所关联的字符串值
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    default <T> T getData(String key, Class clazz){
        return (T) getDataDecode(key).apply(get(SafeEncoder.encode(key)), clazz);
    }

    /**
     * 将 key 的值设为 value ，当且仅当 key 不存在
     * @param key
     * @param value
     * @return
     */
    default Long setnxData(String key, Object value){
        return setnx(SafeEncoder.encode(key), getDataEncode(key).apply(value));
    }

    /**
     * 将给定 key 的值设为 value ，并返回 key 的旧值
     * @param key
     * @param value
     * @return
     */
    default <T> T getsetData(String key, Class clazz, T value){
        return (T) getDataDecode(key).apply(getSet(SafeEncoder.encode(key), getDataEncode(key).apply(value)), clazz);
    }

    /**
     * 将值 value 关联到 key ，并将 key 的生存时间设为 seconds (以秒为单位)
     * @param key
     * @param seconds
     * @param value
     * @return
     */
    default String setexData(String key, int seconds, Object value){
        return setex(SafeEncoder.encode(key), seconds, getDataEncode(key).apply(value));
    }

    /**
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    default Long hsetData(String key, String field, Object value) {
        return hset(SafeEncoder.encode(key), SafeEncoder.encode(field), getDataEncode(key).apply(value));
    }

    /**
     * 返回哈希表 key 中给定域 field 的值
     * @param key
     * @param clazz
     * @param field
     * @param <T>
     * @return
     */
    default <T> T  hgetData(String key, Class clazz, String field) {
        return (T) getDataDecode(key).apply(hget(SafeEncoder.encode(key), SafeEncoder.encode(field)), clazz);
    }

    /**
     * 将哈希表 key 中的域 field 的值设置为 value ，当且仅当域 field 不存在
     * @param key
     * @param field
     * @param value
     * @return
     */
    default Long hsetnxData(String key, String field, Object value) {
        return hsetnx(SafeEncoder.encode(key), SafeEncoder.encode(field), getDataEncode(key).apply(value));
    }

    /**
     * 同时将多个 field-value (域-值)对设置到哈希表 key 中
     * @param key
     * @param hash
     * @return
     */
    default String hmsetData(String key, Map<String, Object> hash){
        Map<byte[],byte[]> param = new HashMap<>();
        Function<Object,byte[]> encode = getDataEncode(key);
        hash.forEach((k,v)-> param.put(SafeEncoder.encode(k),encode.apply(v)));
        return hmset(SafeEncoder.encode(key), param);
    }

    /**
     * 返回哈希表 key 中，一个或多个给定域的值
     * @param key
     * @param fields
     * @return
     */
    default <T> List<T> hmgetData(String key, Class clazz, String... fields){
        List<byte[]> result = hmget(SafeEncoder.encode(key), SafeEncoder.encodeMany(fields));
        BiFunction<byte[],Class<T>,T> decode = getDataDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toList());
    }

    /**
     * 返回哈希表 key 中所有域的值 key field value 返回 values
     * @param key
     * @return
     */
    default <T> List<T> hvalsData(String key, Class clazz){
        Collection<byte[]> result = hvals(SafeEncoder.encode(key));
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toList());
    }

    /**
     * 返回哈希表 key 中，所有的域和值
     * @param key
     * @return Map<域,值>
     */
    default <T> Map<String, T> hgetAllData(String key, Class clazz){
        Map<String,T> result = new HashMap<>();
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        hgetAll(SafeEncoder.encode(key)).forEach((k, v) -> result.put(SafeEncoder.encode(k),(T)decode.apply(v, clazz)));
        return result;
    }

    /**
     * 将一个或多个值 value 插入到列表 key 的表尾(最右边)
     * @param key
     * @param objects
     * @return
     */
    default Long rpushData(String key, Object... objects){
        Function<Object,byte[]> encode = getDataEncode(key);
        return rpush(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                encode.apply(v)).collect(Collectors.toList()).toArray());
    }

    /**
     * 将一个或多个值 value 插入到列表 key 的表头
     * @param key
     * @param objects
     * @return
     */
    default Long lpushData(String key, Object... objects){
        Function<Object,byte[]> encode = getDataEncode(key);
        return lpush(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定
     * @param key
     * @param start
     * @param end
     * @return
     */
    default <T> List<T> lrangeData(String key, Class clazz, long start, long end){
        Collection<byte[]> result = lrange(SafeEncoder.encode(key), start, end);
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toList());
    }

    /**
     * 返回列表 key 中，下标为 index 的元素
     * @param key
     * @param index
     * @return
     */
    default <T> T lindexData(String key, Class clazz, long index){
        return (T) getDataDecode(key).apply(lindex(SafeEncoder.encode(key), index), clazz);
    }

    /**
     * 将列表 key 下标为 index 的元素的值设置为 value
     * @param key
     * @param index
     * @param value
     * @return
     */
    default String lsetData(String key, long index, Object value){
        return lset(SafeEncoder.encode(key), index, getDataEncode(key).apply(value));
    }

    /**
     * 根据参数 count 的值，移除列表中与参数 value 相等的元素
     * @param key
     * @param count  count > 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。
     *                count < 0 : 从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。
     *                count = 0 : 移除表中所有与 value 相等的值
     * @param value
     * @return
     */
    default Long lremData(String key, long count, Object value){
        return lrem(SafeEncoder.encode(key), count, getDataEncode(key).apply(value));
    }

    /**
     *移除并返回列表 key 的头元素
     * @param key
     * @return
     */
    default <T> T lpopData(String key, Class clazz){
        return (T) getDataDecode(key).apply(lpop(SafeEncoder.encode(key)), clazz);
    }

    /**
     * 移除并返回列表 key 的尾元素
     * @param key
     * @return
     */
    default <T> T  rpopData(String key, Class clazz){
        return (T) getDataDecode(key).apply(rpop(SafeEncoder.encode(key)), clazz);
    }

    /**
     * 将一个或多个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略
     * @param key
     * @param member
     * @return
     */
    default Long saddData(String key, Object... member){
        Function<Object,byte[]> encode = getDataEncode(key);
        return sadd(SafeEncoder.encode(key), (byte[][]) Arrays.asList(member).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 返回集合 key 中的所有成员
     * @param key
     * @return
     */
    default <T> Set<T> smembersData(String key, Class clazz){
        Set<byte[]> result = smembers(SafeEncoder.encode(key));
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toSet());
    }

    /**
     * 移除集合 key 中的一个或多个 member 元素，不存在的 member 元素会被忽略
     * @param key
     * @param member
     * @return
     */
    default Long sremData(String key, Object... member){
        Function<Object,byte[]> encode = getDataEncode(key);
        return srem(SafeEncoder.encode(key), (byte[][]) Arrays.asList(member).stream().map(v -> encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 移除并返回集合中的一个随机元素
     * @param key
     * @return
     */
    default <T> T spopData(String key, Class clazz){
        return (T) getDataDecode(key).apply(spop(SafeEncoder.encode(key)), clazz);
    }

    /**
     * 移除并返回集合中的几个随机元素
     * @param key
     * @param count
     * @return
     */
    default <T> Set<T> spopData(String key, Class clazz, long count){
        Set<byte[]> result = spop(SafeEncoder.encode(key),count);
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toSet());
    }

    /**
     * 判断 member 元素是否集合 key 的成员
     * @param key
     * @param member
     * @return
     */
    default Boolean sismemberData(String key, Object member){
        return sismember(SafeEncoder.encode(key), getDataEncode(key).apply(member));
    }

    /**
     * 返回集合中的一个随机元素
     * @param key
     * @return
     */
    default <T> T srandmemberData(String key, Class clazz){
        return (T) getDataDecode(key).apply(srandmember(SafeEncoder.encode(key)), clazz);
    }

    /**
     * 返回集合中的几个随机元素
     * @param key
     * @param count
     * @return
     */
    default <T> List<T> srandmemberData(String key, Class clazz, int count){
        List<byte[]> result = srandmember(SafeEncoder.encode(key),count);
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toList());
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中
     * @param key
     * @param score 排序的值
     * @param member
     * @return
     */
    default Long zaddData(String key, double score, Object member){
        return zadd(SafeEncoder.encode(key), score, getDataEncode(key).apply(member));
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中
     * @param key
     * @param scoreMembers
     * @return
     */
    default Long zaddData(String key, Map<Object, Double> scoreMembers){
        Map<byte[],Double> param = new HashMap<>();
        Function<Object,byte[]> encode = getDataEncode(key);
        scoreMembers.forEach((k,v)-> param.put(encode.apply(k),v));
        return zadd(SafeEncoder.encode(key), param);
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。
     * 其中成员的位置按 score 值递增(从小到大)来排序
     * @param key
     * @param start
     * @param end
     * @return
     */
    default <T> Set<T> zrangeData(String key, Class clazz, long start, long end){
        Set<byte[]> result = zrange(SafeEncoder.encode(key), start, end);
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toSet());
    }

    /**
     * 移除有序集 key 中的一个或多个成员，不存在的成员将被忽略
     * @param key
     * @param member
     * @return
     */
    default Long zremData(String key, Object... member){
        Function<Object,byte[]> encode = getDataEncode(key);
        return zrem(SafeEncoder.encode(key), (byte[][]) Arrays.asList(member).stream().map(v -> encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 为有序集 key 的成员 member 的 score 值加上增量 increment
     * @param key
     * @param score 增加的分值
     * @param member
     * @return
     */
    default Double zincrbyData(String key, double score, Object member){
        return zincrby(SafeEncoder.encode(key), score, getDataEncode(key).apply(member));
    }

    /**
     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列
     * @param key
     * @param member
     * @return
     */
    default Long zrankData(String key, Object member){
        return zrank(SafeEncoder.encode(key), getDataEncode(key).apply(member));
    }

    /**
     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
     * 排名以 0 为底，也就是说， score 值最大的成员排名为 0
     * @param key
     * @param member
     * @return
     */
    default Long zrevrankData(String key, Object member){
        return zrevrank(SafeEncoder.encode(key), getDataEncode(key).apply(member));
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。
     * @param key
     * @param start
     * @param end
     * @return
     */
    default <T> Set<T> zrevrangeData(String key, Class clazz, long start, long end){
        Set<byte[]> result = zrevrange(SafeEncoder.encode(key), start, end);
        BiFunction <byte[],Class<T>,T> decode = getDataDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes, clazz)).collect(Collectors.toSet());
    }

    /**
     * 返回有序集 key 中，成员 member 的 score 值
     * @param key
     * @param member
     * @return
     */
    default Double zscoreData(String key, Object member){
        return zscore(SafeEncoder.encode(key), getDataEncode(key).apply(member));
    }

    /**
     * 将值 value 插入到列表 key 的表头，当且仅当 key 存在并且是一个列表。
     * 和 LPUSH 命令相反，当 key 不存在时， LPUSHX 命令什么也不做
     * @param key
     * @param objects
     * @return
     */
    default Long lpushxData(String key, Object... objects){
        Function<Object,byte[]> encode = getDataEncode(key);
        return lpushx(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 将值 value 插入到列表 key 的表尾，当且仅当 key 存在并且是一个列表。
     * 和 RPUSH 命令相反，当 key 不存在时， RPUSHX 命令什么也不做。
     * @param key
     * @param objects
     * @return
     */
    default Long rpushxData(String key, Object... objects){
        Function<Object,byte[]> encode = getDataEncode(key);
        return rpushx(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }
    //List<String> sort(String key);
    //List<String> sort(String key, SortingParams sortingParameters);
    //Long zcount(String key, double min, double max);
    //Long zcount(String key, String min, String max);
    //Set<String> zrangeByScore(String key, double min, double max);
    //Set<String> zrangeByScore(String key, String min, String max);
    //Set<String> zrevrangeByScore(String key, double max, double min);
    //Set<String> zrangeByScore(String key, double min, double max, int offset, int count);
    //Set<String> zrevrangeByScore(String key, String max, String min);
    //Set<String> zrangeByScore(String key, String min, String max, int offset, int count);
    //Set<String> zrevrangeByScore(String key, double max, double min, int offset, int count);
    //Set<Tuple> zrangeByScoreWithScores(String key, double min, double max);
    //Set<Tuple> zrevrangeByScoreWithScores(String key, double max, double min);
    //Set<Tuple> zrangeByScoreWithScores(String key, double min, double max, int offset, int count);
    //Set<String> zrevrangeByScore(String key, String max, String min, int offset, int count);
    //Set<Tuple> zrangeByScoreWithScores(String key, String min, String max);
    //Set<Tuple> zrevrangeByScoreWithScores(String key, String max, String min);
    //Set<Tuple> zrangeByScoreWithScores(String key, String min, String max, int offset, int count);
    //Set<Tuple> zrevrangeByScoreWithScores(String key, double max, double min, int offset, int count);
    //Set<Tuple> zrevrangeByScoreWithScores(String key, String max, String min, int offset, int count);
    //Long zremrangeByRank(String key, long start, long end);
    //Long zremrangeByScore(String key, double start, double end);
    //Long zremrangeByScore(String key, String start, String end);
    //Long zlexcount(final String key, final String min, final String max);
    //Set<String> zrangeByLex(final String key, final String min, final String max);
    //Set<String> zrangeByLex(final String key, final String min, final String max, final int offset,final int count);
    //Set<String> zrevrangeByLex(final String key, final String max, final String min);
    //Set<String> zrevrangeByLex(final String key, final String max, final String min,final int offset, final int count);
    //Long zremrangeByLex(final String key, final String min, final String max);
    //Long linsert(String key, Client.LIST_POSITION where, String pivot, String value);
    //Long pfadd(final String key, final String... elements);
    //Set<Tuple> zrangeWithScores(String key, long start, long end);
    //Set<Tuple> zrevrangeWithScores(String key, long start, long end);
    //Long zcard(String key);



    /**
     * 将字符串值 value 关联到 key 。如果 key 已经持有其他值， SET 就覆写旧值，无视类型。
     * 对于某个原本带有生存时间（TTL）的键来说， 当 SET 命令成功在这个键上执行时， 这个键原有的 TTL 将被清除
     * @param key
     * @param value
     * @return
     */
    default String setObject(String key, Object value){
        return set(SafeEncoder.encode(key), getObjectEncode(key).apply(value));
    }

    /**
     * EX second ：设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
     * PX millisecond ：设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
     * NX ：只在键不存在时，才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
     * XX ：只在键已经存在时，才对键进行设置操作。
     * @param key
     * @param value
     * @param nxxx
     * @param expx
     * @param time
     * @return
     */
    default String setObject(String key, Object value, String nxxx, String expx, long time){
        return set(SafeEncoder.encode(key), getObjectEncode(key).apply(value), SafeEncoder.encode(nxxx), SafeEncoder.encode(expx), time);
    }

    /**
     * 返回 key 所关联的字符串值
     * @param key
     * @param <T>
     * @return
     */
    default <T> T getObject(String key){
        return (T) getObjectDecode(key).apply(get(SafeEncoder.encode(key)));
    }

    /**
     * 将 key 的值设为 value ，当且仅当 key 不存在
     * @param key
     * @param value
     * @return
     */
    default Long setnxObject(String key, Object value){
        return setnx(SafeEncoder.encode(key), getObjectEncode(key).apply(value));
    }

    /**
     * 将给定 key 的值设为 value ，并返回 key 的旧值
     * @param key
     * @param value
     * @return
     */
    default <T> T getsetObject(String key, T value){
        return (T) getObjectDecode(key).apply(getSet(SafeEncoder.encode(key), getObjectEncode(key).apply(value)));
    }

    /**
     * 将值 value 关联到 key ，并将 key 的生存时间设为 seconds (以秒为单位)
     * @param key
     * @param seconds
     * @param value
     * @return
     */
    default String setexObject(String key, int seconds, Object value){
        return setex(SafeEncoder.encode(key), seconds, getObjectEncode(key).apply(value));
    }

    /**
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    default Long hsetObject(String key, String field, Object value) {
        return hset(SafeEncoder.encode(key), SafeEncoder.encode(field), getObjectEncode(key).apply(value));
    }

    /**
     * 返回哈希表 key 中给定域 field 的值
     * @param key
     * @param field
     * @param <T>
     * @return
     */
    default <T> T  hgetObject(String key, String field) {
        return (T) getObjectDecode(key).apply(hget(SafeEncoder.encode(key), SafeEncoder.encode(field)));
    }

    /**
     * 将哈希表 key 中的域 field 的值设置为 value ，当且仅当域 field 不存在
     * @param key
     * @param field
     * @param value
     * @return
     */
    default Long hsetnxObject(String key, String field, Object value) {
        return hsetnx(SafeEncoder.encode(key), SafeEncoder.encode(field), getObjectEncode(key).apply(value));
    }

    /**
     * 同时将多个 field-value (域-值)对设置到哈希表 key 中
     * @param key
     * @param hash
     * @return
     */
    default String hmsetObject(String key, Map<String, Object> hash){
        Map<byte[],byte[]> param = new HashMap<>();
        Function<Object,byte[]> encode = getObjectEncode(key);
        hash.forEach((k,v)-> param.put(SafeEncoder.encode(k),encode.apply(v)));
        return hmset(SafeEncoder.encode(key), param);
    }

    /**
     * 返回哈希表 key 中，一个或多个给定域的值
     * @param key
     * @param fields
     * @return
     */
    default <T> List<T> hmgetObject(String key, String... fields){
        List<byte[]> result = hmget(SafeEncoder.encode(key), SafeEncoder.encodeMany(fields));
        Function<byte[],Object> decode = getObjectDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toList());
    }

    /**
     * 返回哈希表 key 中所有域的值 key field value 返回 values
     * @param key
     * @return
     */
    default <T> List<T> hvalsObject(String key){
        Collection<byte[]> result = hvals(SafeEncoder.encode(key));
        Function <byte[],Object> decode = getObjectDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toList());
    }

    /**
     * 返回哈希表 key 中，所有的域和值
     * @param key
     * @return Map<域,值>
     */
    default <T> Map<String, T> hgetAllObject(String key){
        Map<String,T> result = new HashMap<>();
        Function <byte[],Object> decode = getObjectDecode(key);
        hgetAll(SafeEncoder.encode(key)).forEach((k, v) -> result.put(SafeEncoder.encode(k),(T)decode.apply(v)));
        return result;
    }

    /**
     * 将一个或多个值 value 插入到列表 key 的表尾(最右边)
     * @param key
     * @param objects
     * @return
     */
    default Long rpushObject(String key, Object... objects){
        Function<Object,byte[]> encode = getObjectEncode(key);
        return rpush(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                encode.apply(v)).collect(Collectors.toList()).toArray());
    }

    /**
     * 将一个或多个值 value 插入到列表 key 的表头
     * @param key
     * @param objects
     * @return
     */
    default Long lpushObject(String key, Object... objects){
        Function<Object,byte[]> encode = getObjectEncode(key);
        return lpush(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定
     * @param key
     * @param start
     * @param end
     * @return
     */
    default <T> List<T> lrangeObject(String key, long start, long end){
        Collection<byte[]> result = lrange(SafeEncoder.encode(key), start, end);
        Function <byte[],Object> decode = getObjectDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toList());
    }

    /**
     * 返回列表 key 中，下标为 index 的元素
     * @param key
     * @param index
     * @return
     */
    default <T> T lindexObject(String key, long index){
        return (T) getObjectDecode(key).apply(lindex(SafeEncoder.encode(key), index));
    }

    /**
     * 将列表 key 下标为 index 的元素的值设置为 value
     * @param key
     * @param index
     * @param value
     * @return
     */
    default String lsetObject(String key, long index, Object value){
        return lset(SafeEncoder.encode(key), index, getObjectEncode(key).apply(value));
    }

    /**
     * 根据参数 count 的值，移除列表中与参数 value 相等的元素
     * @param key
     * @param count  count > 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。
     *                count < 0 : 从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。
     *                count = 0 : 移除表中所有与 value 相等的值
     * @param value
     * @return
     */
    default Long lremObject(String key, long count, Object value){
        return lrem(SafeEncoder.encode(key), count, getObjectEncode(key).apply(value));
    }

    /**
     *移除并返回列表 key 的头元素
     * @param key
     * @return
     */
    default <T> T lpopObject(String key){
        return (T) getObjectDecode(key).apply(lpop(SafeEncoder.encode(key)));
    }

    /**
     * 移除并返回列表 key 的尾元素
     * @param key
     * @return
     */
    default <T> T  rpopObject(String key){
        return (T) getObjectDecode(key).apply(rpop(SafeEncoder.encode(key)));
    }

    /**
     * 将一个或多个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略
     * @param key
     * @param member
     * @return
     */
    default Long saddObject(String key, Object... member){
        Function<Object,byte[]> encode = getObjectEncode(key);
        return sadd(SafeEncoder.encode(key), (byte[][]) Arrays.asList(member).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 返回集合 key 中的所有成员
     * @param key
     * @return
     */
    default <T> Set<T> smembersObject(String key){
        Set<byte[]> result = smembers(SafeEncoder.encode(key));
        Function <byte[],Object> decode = getObjectDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toSet());
    }

    /**
     * 移除集合 key 中的一个或多个 member 元素，不存在的 member 元素会被忽略
     * @param key
     * @param member
     * @return
     */
    default Long sremObject(String key, Object... member){
        Function<Object,byte[]> encode = getObjectEncode(key);
        return srem(SafeEncoder.encode(key), (byte[][]) Arrays.asList(member).stream().map(v -> encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 移除并返回集合中的一个随机元素
     * @param key
     * @return
     */
    default <T> T spopObject(String key){
        return (T) getObjectDecode(key).apply(spop(SafeEncoder.encode(key)));
    }

    /**
     * 移除并返回集合中的几个随机元素
     * @param key
     * @param count
     * @return
     */
    default <T> Set<T> spopObject(String key, long count){
        Set<byte[]> result = spop(SafeEncoder.encode(key),count);
        Function <byte[],Object> decode = getObjectDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toSet());
    }

    /**
     * 判断 member 元素是否集合 key 的成员
     * @param key
     * @param member
     * @return
     */
    default Boolean sismemberObject(String key, Object member){
        return sismember(SafeEncoder.encode(key), getObjectEncode(key).apply(member));
    }

    /**
     * 返回集合中的一个随机元素
     * @param key
     * @return
     */
    default <T> T srandmemberObject(String key){
        return (T) getObjectDecode(key).apply(srandmember(SafeEncoder.encode(key)));
    }

    /**
     * 返回集合中的几个随机元素
     * @param key
     * @param count
     * @return
     */
    default <T> List<T> srandmemberObject(String key, int count){
        List<byte[]> result = srandmember(SafeEncoder.encode(key),count);
        Function <byte[],Object> decode = getObjectDecode(key);
        return (List<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toList());
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中
     * @param key
     * @param score 排序的值
     * @param member
     * @return
     */
    default Long zaddObject(String key, double score, Object member){
        return zadd(SafeEncoder.encode(key), score, getObjectEncode(key).apply(member));
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中
     * @param key
     * @param scoreMembers
     * @return
     */
    default Long zaddObject(String key, Map<Object, Double> scoreMembers){
        Map<byte[],Double> param = new HashMap<>();
        Function<Object,byte[]> encode = getObjectEncode(key);
        scoreMembers.forEach((k,v)-> param.put(encode.apply(k),v));
        return zadd(SafeEncoder.encode(key), param);
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。
     * 其中成员的位置按 score 值递增(从小到大)来排序
     * @param key
     * @param start
     * @param end
     * @return
     */
    default <T> Set<T> zrangeObject(String key, long start, long end){
        Set<byte[]> result = zrange(SafeEncoder.encode(key), start, end);
        Function <byte[],Object> decode = getObjectDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toSet());
    }

    /**
     * 移除有序集 key 中的一个或多个成员，不存在的成员将被忽略
     * @param key
     * @param member
     * @return
     */
    default Long zremObject(String key, Object... member){
        Function<Object,byte[]> encode = getObjectEncode(key);
        return zrem(SafeEncoder.encode(key), (byte[][]) Arrays.asList(member).stream().map(v -> encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 为有序集 key 的成员 member 的 score 值加上增量 increment
     * @param key
     * @param score 增加的分值
     * @param member
     * @return
     */
    default Double zincrbyObject(String key, double score, Object member){
        return zincrby(SafeEncoder.encode(key), score, getObjectEncode(key).apply(member));
    }

    /**
     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列
     * @param key
     * @param member
     * @return
     */
    default Long zrankObject(String key, Object member){
        return zrank(SafeEncoder.encode(key), getObjectEncode(key).apply(member));
    }

    /**
     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
     * 排名以 0 为底，也就是说， score 值最大的成员排名为 0
     * @param key
     * @param member
     * @return
     */
    default Long zrevrankObject(String key, Object member){
        return zrevrank(SafeEncoder.encode(key), getObjectEncode(key).apply(member));
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。
     * @param key
     * @param start
     * @param end
     * @return
     */
    default <T> Set<T> zrevrangeObject(String key, long start, long end){
        Set<byte[]> result = zrevrange(SafeEncoder.encode(key), start, end);
        Function <byte[],Object> decode = getObjectDecode(key);
        return (Set<T>)result.stream().map((bytes) -> decode.apply(bytes)).collect(Collectors.toSet());
    }

    /**
     * 返回有序集 key 中，成员 member 的 score 值
     * @param key
     * @param member
     * @return
     */
    default Double zscoreObject(String key, Object member){
        return zscore(SafeEncoder.encode(key), getObjectEncode(key).apply(member));
    }

    /**
     * 将值 value 插入到列表 key 的表头，当且仅当 key 存在并且是一个列表。
     * 和 LPUSH 命令相反，当 key 不存在时， LPUSHX 命令什么也不做
     * @param key
     * @param objects
     * @return
     */
    default Long lpushxObject(String key, Object... objects){
        Function<Object,byte[]> encode = getObjectEncode(key);
        return lpushx(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

    /**
     * 将值 value 插入到列表 key 的表尾，当且仅当 key 存在并且是一个列表。
     * 和 RPUSH 命令相反，当 key 不存在时， RPUSHX 命令什么也不做。
     * @param key
     * @param objects
     * @return
     */
    default Long rpushxObject(String key, Object... objects){
        Function<Object,byte[]> encode = getObjectEncode(key);
        return rpushx(SafeEncoder.encode(key), (byte[][]) Arrays.asList(objects).stream().map(v ->
                        encode.apply(v)
        ).collect(Collectors.toList()).toArray());
    }

}
